package cn.lyjuan.payment.third.base.model.pay.service;

import cn.lyjuan.base.exception.util.ErrUtils;
import cn.lyjuan.base.util.SpringContextHolder;
import cn.lyjuan.payment.third.base.common.entity.pay.PayIapEntity;
import cn.lyjuan.payment.third.base.common.entity.pay.PayTranEntity;
import cn.lyjuan.payment.third.base.common.enums.impl.PayStatusEnum;
import cn.lyjuan.payment.third.base.model.app.domain.AppModel;
import cn.lyjuan.payment.third.base.model.app.service.AppService;
import cn.lyjuan.payment.third.base.model.chl.domain.AppChlModel;
import cn.lyjuan.payment.third.base.model.chl.domain.ChlCnfScanner;
import cn.lyjuan.payment.third.base.model.chl.domain.IChlCnfModel;
import cn.lyjuan.payment.third.base.model.chl.service.AppChlService;
import cn.lyjuan.payment.third.base.model.exception.ErrCodeImpl;
import cn.lyjuan.payment.third.base.model.pay.domain.PayModel;
import cn.lyjuan.payment.third.base.model.pay.vo.NotifyResVo;
import cn.lyjuan.payment.third.base.pay.chl.IPayChl;
import cn.lyjuan.payment.third.base.pay.chl.PayChlScanner;
import cn.lyjuan.payment.third.base.pay.chl.impl.iap.bean.LatestReceiptInfoVo;
import cn.lyjuan.payment.third.base.pay.chl.impl.iap.bean.UniReceiptVo;
import cn.lyjuan.payment.third.base.pay.chl.impl.iap.util.IapSubmit;
import cn.lyjuan.payment.third.base.pay.enums.IosNotifyTypeEnum;
import cn.lyjuan.payment.third.base.pay.enums.SimpleChlEnum;
import cn.lyjuan.payment.third.base.pay.vo.req.PayReq;
import cn.lyjuan.payment.third.base.pay.vo.req.TransferReq;
import cn.lyjuan.payment.third.base.pay.vo.res.PayRes;
import cn.lyjuan.payment.third.base.pay.vo.res.TransferRes;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class PayService {
    @Autowired
    private AppService appService;
    @Autowired
    private AppChlService appChlService;

    /**
     * 交易下单
     *
     * @param app
     * @param chlModel
     * @param appTranNo
     * @param goods
     * @param flag
     * @param amt
     * @param notifyUrl
     * @param returnUrl
     * @param params    支付平台独立参数
     * @return 支付平台交易信息
     */
    public PayRes order(AppModel app, AppChlModel chlModel,
                        String appTranNo, String goods, String flag, Integer amt,
                        String notifyUrl, String returnUrl,
                        PayReq.IPayReq params) {
        PayModel pay = newInstance();

        // 支付渠道
        IPayChl payChl = PayChlScanner.dispatch(chlModel.getEntity().getChlType().getSimpleChlEnum());

        // 配置
        IChlCnfModel chlCnfModel = chlModel.dispatch();

        // 生成交易订单, 返回支付平台交易信息
        PayRes ret = pay.pay(payChl, chlCnfModel.pkg(), app.getEntity().getId(), chlModel.getEntity().getId(),
                chlModel.getEntity().getChlType(), appTranNo, goods, flag, amt, notifyUrl, returnUrl, params
        );

        return ret;
    }

    /**
     * 转账
     *
     * @param app       app
     * @param chlModel  支付渠道
     * @param appTranNo orderNo
     * @param title     标题
     * @param identity  身份
     * @param remark    备注
     * @param flag      回调带上的额外参数
     * @param amt       金额
     * @param params    参数
     * @return TransferRes
     */
    public TransferRes transfer(AppModel app, AppChlModel chlModel, String appTranNo, String title, String identity,
                                String realName, String remark, String flag, Integer amt, TransferReq.ITransferReq params
    ) {
        PayModel pay = newInstance();
        // 支付渠道
        IPayChl payChl = PayChlScanner.dispatch(chlModel.getEntity().getChlType().getSimpleChlEnum());
        // 配置
        IChlCnfModel chlCnfModel = chlModel.dispatch();
        // 生成交易订单, 返回支付平台交易信息
        TransferRes ret = pay.transfer(payChl, chlCnfModel.pkg(), app.getEntity().getId(), chlModel.getEntity().getId(),
                chlModel.getEntity().getChlType(), appTranNo, title, identity, realName, remark, flag, amt, params);
        return ret;
    }

    /**
     * 处理Ios内购回调
     *
     * @param password          共享秘钥
     * @param notification_type 通知类型
     * @param uniReceiptVo      数据
     */
    public void handleIosNotify(String password, String notification_type, UniReceiptVo uniReceiptVo) {
        IosNotifyTypeEnum tmpEnum = IosNotifyTypeEnum.findByType(notification_type);
        if (tmpEnum == null) {
            log.error("not support ios notify type: [{}]", notification_type);
            return;
        }
        // get List LatestReceiptVo
        List<LatestReceiptInfoVo> infoVoList = uniReceiptVo.getLatest_receipt_info();
        // sort
        IapSubmit.sort(infoVoList);
        // get origin receipt
        LatestReceiptInfoVo originData = infoVoList.get(0);
        // get model
        PayModel pay = newInstance();
        Long originTranId = Long.parseLong(originData.getOriginal_transaction_id());
        // get self iap data by origin data
        PayIapEntity iapData = pay.queryIap(originTranId);
        if (iapData == null) {
            // todo: wait for confirm this situation solution
            return;
        }
        // get iap bind localNo
        PayTranEntity payTranEntity = pay.queryTran(iapData.getLocalNo());
        // 支付渠道
        @SuppressWarnings("all")
        IPayChl payChl = PayChlScanner.dispatch(SimpleChlEnum.IAP);
        // 配置
        AppChlModel appChlModel = appChlService.query(payTranEntity.getAppId(), payTranEntity.getChlType());
        if (null == appChlModel) {
            log.error("handle ios notify error: can't find app iap config: localNo: [{}] appId: [{}] chlType: [{}]",
                    iapData.getLocalNo(), payTranEntity.getAppId(), payTranEntity.getChlType()
            );
            return;
        }
        // get config
        IChlCnfModel chlCnfModel = appChlModel.dispatch();
        // check password
        if (!chlCnfModel.pkg().getKey().equals(password)) {
            return;
        }
        pay.handleIosNotify(tmpEnum, infoVoList, iapData, payTranEntity);
    }

    /**
     * 查询交易信息
     *
     * @param localNo localNo
     * @return {@code null}不存在的应用交易流水号
     */
    public PayModel query(String localNo) {
        PayModel payModel = newInstance();
        boolean exist = payModel.query(localNo);

        return exist ? payModel : null;
    }

    /**
     * 支付平台通知
     */
    public NotifyResVo notifyStatus(String appTranNo) {
        PayModel payModel = query(appTranNo);
        if (null == payModel) {
            ErrUtils.appThrow(ErrCodeImpl.PAY_APP_TRAN_NO_NOT_FOUND);
        }

        AppModel app = appService.query(payModel.getEntity().getAppId());

        // 交易渠道
        IPayChl payChl = PayChlScanner.dispatch(payModel.getEntity().getChlType().getSimpleChlEnum());
        // 配置
        IChlCnfModel cnfModel = ChlCnfScanner.dispatch(payModel.getEntity().getChlType());
        cnfModel.query(app.getEntity().getId());

        // 处理通知
        return payModel.notifyResult(app, payChl, cnfModel.pkg());
    }

    /**
     * 查询状态
     */
    public PayStatusEnum queryStatus(String localNo, AppChlModel appChlModel, Map<String, String> params) {
        PayModel payModel = query(localNo);
        if (null == payModel)
            ErrUtils.appThrow(ErrCodeImpl.PAY_APP_TRAN_NO_NOT_FOUND);

        AppModel app = appService.query(payModel.getEntity().getAppId());

        // 交易渠道
        IPayChl payChl = PayChlScanner.dispatch(payModel.getEntity().getChlType().getSimpleChlEnum());
        // 配置
        IChlCnfModel chlCnfModel = appChlModel.dispatch();

        PayStatusEnum status = payModel.queryResult(app, payChl, chlCnfModel.pkg(), params);

        return status;
    }

    public AlipayUserInfoShareResponse auth(AppModel appModel,AppChlModel appChlModel, String authCode) {
        PayModel pay = newInstance();

        // 支付渠道
        IPayChl payChl = PayChlScanner.dispatch(appChlModel.getEntity().getChlType().getSimpleChlEnum());

        // 配置
        IChlCnfModel chlCnfModel = appChlModel.dispatch();
        return null;
    }

    public PayStatusEnum orderRefund(String appRefundNo, String localNo, AppModel app, AppChlModel appChlModel, Integer amt, PayModel payModel) {

        // 交易渠道
        IPayChl payChl = PayChlScanner.dispatch(payModel.getEntity().getChlType().getSimpleChlEnum());
        // 配置
        IChlCnfModel chlCnfModel = appChlModel.dispatch();
        // handle
        boolean status = payModel.orderRefund(app, payChl, chlCnfModel.pkg(), appChlModel.getEntity().getTranFee(), amt, appRefundNo);
        if (!status) {
            return PayStatusEnum.FAIL;
        }
        return PayStatusEnum.SUCC;
    }

    private PayModel newInstance() {
        return SpringContextHolder.getBean(PayModel.class);
    }
}
